DEFINT A-Z

DIM IP(4) AS INTEGER,MASK(4) AS INTEGER,MASKN AS INTEGER
DIM NET(4) AS INTEGER,BRD(4) AS INTEGER,ST(4) AS INTEGER,FIN(4) AS INTEGER

PRINT "*** IPv4 Calculator ***"
CALL INPUTIP(IP())
CALL INPUTMASK(MASK(),MASKN)
FOR I=0 TO 3
  NET(I)=IP(I) AND MASK(I)
  BRD(I)=IP(I) OR (NOT(MASK(I)) AND 255)
  ST(I)=NET(I):FIN(I)=BRD(I)
NEXT I
ST(3)=ST(3)+1:FIN(3)=FIN(3)-1
TSIZE=30
PRINT""
PRINT "IP Address:";TAB(TSIZE);IPSTR$(IP())
PRINT "Subnet Mask:";TAB(TSIZE);IPSTR$(MASK());" (/";LTRIM$(RTRIM$(STR$(MASKN)));")"
PRINT "Network Address:";TAB(TSIZE);IPSTR$(NET())
PRINT "Broadcast Address:";TAB(TSIZE);IPSTR$(BRD())
PRINT "Available Hosts:";TAB(TSIZE);LTRIM$(STR$(CLNG(2)^(32-MASKN)-2))
PRINT "Available Host Range:";TAB(TSIZE);IPSTR$(ST());" - ";IPSTR$(FIN())

SUB INPUTIP(IP() AS INTEGER)
  STATIC PASSED,S$
  PASSED=0:WHILE PASSED=0:PASSED=1
  INPUT "Input IP:",S$:CALL PARSEIP(S$,IP())
  IF IP(0)<0 THEN PASSED=0:PRINT "Invalid Input."
  WEND
END SUB

SUB INPUTMASK(MASK() AS INTEGER,CIDR AS INTEGER)
  STATIC PASSED,S$
  PASSED=0:WHILE PASSED=0:PASSED=1
    INPUT "Input Subnet Mask:",S$:S$=LTRIM$(RTRIM$(S$))
    CALL PARSEMASK(S$,MASK(),CIDR)
    IF CIDR<0 THEN PASSED=0:PRINT "Invalid Input."
  WEND
END SUB

SUB PARSEIP(S AS STRING,IP() AS INTEGER)
  STATIC I AS INTEGER,N AS INTEGER,P AS INTEGER,P0 AS INTEGER
  STATIC SP AS STRING
  P0=1:FOR I=0 TO 3:P=INSTR(P0,S,".")
    IF (I<3 AND P=0) OR (I=3 AND P<>0) THEN IP(0)=-1:EXIT SUB
    IF P=0 THEN SP=MID$(S,P0) ELSE SP=MID$(S,P0,P-P0)
    SP=LTRIM$(RTRIM$(SP)):IF ISNUM(SP)=0 THEN IP(0)=-1:EXIT SUB
    N=VAL(SP):IF N<0 OR N>255 THEN IP(0)=-1:EXIT SUB
    IP(I)=N:P0=P+1
  NEXT I
END SUB

SUB PARSEMASK(S AS STRING,M() AS INTEGER,N AS INTEGER)
  STATIC I,SP,A AS LONG
  IF ISNUM(S)=0 THEN
    CALL PARSEIP(S,M()):IF M(0)<128 THEN N=-1:EXIT SUB
    A=0:FOR I=0 TO 3:A=A*256:A=A OR (NOT(M(I)) AND 255):NEXT I
    IF A<>&H7FFFFFFF THEN IF (A AND (A+1))<>0 THEN N=-1:EXIT SUB
    N=0:WHILE A<>0:A=A AND (A-1):N=N+1:WEND:N=32-N
    IF N<1 OR N>30 THEN N=-1:EXIT SUB
  ELSE
    N=VAL(S):IF N<1 OR N>30 THEN N=-1:EXIT SUB
    SP=N\8:FOR I=0 TO 3
      IF I<SP THEN M(I)=255 ELSE IF I>SP THEN M(I)=0 ELSE M(I)=NOT(2^(8-(N AND 7))-1) AND 255
    NEXT I
  END IF
END SUB

FUNCTION IPSTR$(IP() AS INTEGER)
  STATIC I AS INTEGER,S AS STRING
  S=""
  FOR I=0 TO 3
    S=S+LTRIM$(RTRIM$(STR$(IP(I))))
    IF I<3 THEN S=S+"."
  NEXT I
  IPSTR$=S
END FUNCTION

FUNCTION ISNUM(S AS STRING)
  STATIC I AS INTEGER,C AS STRING
  ISNUM=0
  IF LEN(S)=0 THEN EXIT FUNCTION
  FOR I=1 TO LEN(S):C=MID$(S,I,1)
    IF C<"0" OR C>"9" THEN EXIT FUNCTION
  NEXT I
  ISNUM=1
END FUNCTION

